package compiler.ast;

import java.io.PrintStream;

import compiler.tac.BasicBlock;
import compiler.tac.ThreeAddressCode;

public class Relation {
	public enum Operator {
		EQ("="), NE("#"), LT("<"), LE("<="), GT(">"), GE(">=");
		
		private String value;
		
		private Operator(String value) {
			this.value = value;
		}
		
		public String value() {
			return value;
		}
		
		static public Operator fromString(String val) {
			for (Operator oprt : values()) {
				if (oprt.value.equals(val)) {
					return oprt;
				}
			}
			
			return null;
		}
	}
	
	Operator oprt;
	Expression left;
	Expression right;
	
	public Relation(Operator oprt, Expression left, Expression right) {
		this.oprt = oprt;
		this.left = left;
		this.right = right;
	}
	
	public Relation(String oprt, Expression left, Expression right) {
		this.oprt = Operator.fromString(oprt);
		this.left = left;
		this.right = right;
	}
	
	public compiler.tac.Instruction.Operator getBranchOprt() {
		compiler.tac.Instruction.Operator boprt = null;
		switch (oprt) {
		case EQ:
			boprt = compiler.tac.Instruction.Operator.Beq;
			break;
		case GE:
			boprt = compiler.tac.Instruction.Operator.Bge;
			break;
		case GT:
			boprt = compiler.tac.Instruction.Operator.Bgt;
			break;
		case LE:
			boprt = compiler.tac.Instruction.Operator.Ble;
			break;
		case LT:
			boprt = compiler.tac.Instruction.Operator.Blt;
			break;
		case NE:
			boprt = compiler.tac.Instruction.Operator.Bne;
			break;
		}
		
		return boprt;
	}
	
	public compiler.tac.Instruction.Operator getNegatedBranchOprt() {
		compiler.tac.Instruction.Operator boprt = null;
		switch (oprt) {
		case EQ:
			boprt = compiler.tac.Instruction.Operator.Bne;
			break;
		case GE:
			boprt = compiler.tac.Instruction.Operator.Blt;
			break;
		case GT:
			boprt = compiler.tac.Instruction.Operator.Ble;
			break;
		case LE:
			boprt = compiler.tac.Instruction.Operator.Bgt;
			break;
		case LT:
			boprt = compiler.tac.Instruction.Operator.Bge;
			break;
		case NE:
			boprt = compiler.tac.Instruction.Operator.Beq;
			break;
		}
		
		return boprt;
	}
	
	public void printDotFormat(PrintStream out, String node) {
		out.println(node+" [label=\"Rel "+oprt.name()+"\"];");
		
		out.println(node+"->"+node+"0;");
		left.printDotFormat(out, node+0);

		out.println(node+"->"+node+"1;");
		right.printDotFormat(out, node+1);
	}

	public String toThreeAddressCode(ThreeAddressCode tac, BasicBlock prev) {
		String lt = left.toThreeAddressCode(tac, prev);
		String rt = right.toThreeAddressCode(tac, prev);
		
		String cmpt = tac.getTempVar();
		prev.addBinaryInstruction(compiler.tac.Instruction.Operator.Cmp, cmpt, lt, rt);
		
		return cmpt;
	}
}
